﻿/*********************************************************************************
**                                                                              **
**  Copyright (C) 2022-2022 LiLong                                              **
**  This file is part of BluetoothCpp.                                          **
**                                                                              **
**  BluetoothCpp is free software: you can redistribute it and/or modify        **
**  it under the terms of the GNU Lesser General Public License as published by **
**  the Free Software Foundation, either version 3 of the License, or           **
**  (at your option) any later version.                                         **
**                                                                              **
**  BluetoothCpp is distributed in the hope that it will be useful,             **
**  but WITHOUT ANY WARRANTY; without even the implied warranty of              **
**  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               **
**  GNU Lesser General Public License for more details.                         **
**                                                                              **
**  You should have received a copy of the GNU Lesser General Public License    **
**  along with BluetoothCpp.  If not, see <https://www.gnu.org/licenses/>.      **
**********************************************************************************/
#pragma once

#include "Address.h"
#include "Uuid.h"

#include <chrono>
#include <iostream>
#include <memory>

#ifdef WIN32
struct _BLUETOOTH_DEVICE_INFO;
#endif

namespace BTH
{
class BTH_EXPORT Device
{
public:
    enum class MajorDeviceClass : unsigned char
    {
        Miscellaneous = 0x0000,
        Computer      = 0x0001,
        Phone         = 0x0002,
        AccessPoint   = 0x0003,
        AudioVedio    = 0x0004,
        Peripheral    = 0x0005,
        Imaging       = 0x0006,
        Wearable      = 0x0007,
        Toy           = 0x0008,
        Health        = 0x0009,
        Uncategorized = 0x001F
    };

    enum class ComputerClass : unsigned char
    {
        DesktopComputer = 0x01,
        ServerComputer,
        LaptopComputer,
        HandheldComputer,
        PdaComputer,
        WearableComputer
    };

    enum class PhoneClass : unsigned char
    {
        CellPhone = 0x01,
        CordlessPhone,
        SmartPhone,
        WiredPhone,
        IsdnAccess
    };

    enum class AccessPoint : unsigned char
    {
        AccessPointFullAvailable,
        AccessPoint1To17,
        AccessPoint17To33,
        AccessPoint33To50,
        AccessPoint50To67,
        AccessPoint67To83,
        AccessPoint83To99,
        AccessPointNoService
    };

    enum class AudioVedioClass : unsigned char
    {
        AudioVideoUnclassified,
        AudioVideoHeadset,
        AudioVideoHandsFree,
        AudioVideoMicrophone = AudioVideoHandsFree + 2,
        AudioVideoLoudSpeaker,
        AudioVideoHeadphones,
        AudioVideoPortable,
        AudioVideoCar,
        AudioVideoSetTopBox,
        AudioVideoHiFi,
        AudioVideoVcr,
        AudioVideoVideoCamera,
        AudioVideoCamcorder,
        AudioVideoMonitor,
        AudioVideoDisplayLoudSpeaker,
        AudioVideoVideoConferencing,
        AudioVideoGaming = AudioVideoVideoConferencing + 2
    };

    enum class PeripheralClass
    {
        PeripheralJoystick = 0x01,
        PeripheralGamepad,
        PeripheralRemoteControl,
        PeripheralSensingDevice,
        PeripheralDigitizerTablet,
        PeripheralCardReader,
        PeripheralDigitalPen,
        PeripheralHandheldScannerForBarCodes,
        PeripheralHandheldGesturalInputDevice,
        PeripheralKeyboard                       = 0x10,
        PeripheralPointingDevice                 = 0x20,
        PeripheralCombinedKeyboardPointingDevice = 0x30,
    };

    enum class ImagingClass : unsigned char
    {
        ImagingDisplay = 0x01,
        ImagingCamera  = 0x02,
        ImagingScanner = 0x04,
        ImagingPrinter = 0x08
    };

    enum class WearableClass : unsigned char
    {
        WearableWristWatch = 0x01,
        WearablePager,
        WearableJacket,
        WearableHelmet,
        WearableGlasses
    };

    enum class ToyClass : unsigned char
    {
        ToyRobot = 0x01,
        ToyVehicle,
        ToyFigure,
        ToyController,
        ToyGame
    };

    enum class DeviceClass : unsigned char
    {
        HealthBloodPressureMonitor = 0x01,
        HealthThermometer,
        HealthWeighingScale,
        HealthGlucoseMeter,
        HealthPulseOximeter,
        HealthHeartPulseRateMonitor,
        HealthDataDisplay,
        HealthStepCounter,
        HealthBodyCompositionAnalyzer,
        HealthPeakFlowMonitor,
        HealthMedicationMonitor,
        HealthKneeProsthesis,
        HealthAnkleProsthesis,
        HealthGenericHealthManager,
        HealthPersonalMobilityDevice
    };

    enum ServiceClass : unsigned short
    {
        None                    = 0x0000,
        LimitedDiscoverableMode = 0x0001,
        LEAudio                 = 0x0002,
        Positioning             = 0x0008,
        Network                 = 0x0010,
        Rendering               = 0x0020,
        Capturing               = 0x0040,
        ObjectTransfer          = 0x0080,
        Audio                   = 0x0100,
        Telephony               = 0x0200,
        Information             = 0x0400
    };

    Device() noexcept;
    Device(Device&& rhs) noexcept;
    Device(const Device& rhs) noexcept;
    ~Device() noexcept;

    void setAddress(const Address& addr) noexcept;
    [[nodiscard]] const Address& address() const noexcept;
    void setName(std::string_view name) noexcept;
    [[nodiscard]] const std::string& name() const noexcept;
    [[nodiscard]] bool isConnected() const noexcept;
    [[nodiscard]] bool isRemembered() const noexcept;
    [[nodiscard]] bool isAuthenticated() const noexcept;
    [[nodiscard]] MajorDeviceClass majorDeviceClass() const noexcept;
    [[nodiscard]] unsigned char minorDeviceClass() const noexcept;
    [[nodiscard]] ServiceClass serviceClass() const noexcept;
    [[nodiscard]] const std::chrono::time_point<std::chrono::system_clock>& lastSeenTime() const noexcept;
    [[nodiscard]] const std::chrono::time_point<std::chrono::system_clock>& lastUsedTime() const noexcept;

    Device& operator=(const Device& rhs) noexcept;
    Device& operator=(Device&& rhs) noexcept;
    [[nodiscard]] static std::vector<Device> findDevices();

private:
    void setConnected(bool connected) noexcept;
    void setRemembered(bool remembered) noexcept;
    void setAuthenticated(bool authenticated) noexcept;
    void setMajorDeviceClass(MajorDeviceClass c) noexcept;
    void setMinorDeviceClass(unsigned char minor) noexcept;
    void setServiceClass(ServiceClass sc) noexcept;
    void setLastSeenTime(const std::chrono::time_point<std::chrono::system_clock>& time) noexcept;
    void setLastUsedTime(const std::chrono::time_point<std::chrono::system_clock>& time) noexcept;
#ifdef WIN32
    Device(const _BLUETOOTH_DEVICE_INFO& info);
#endif
private:
    struct Impl;
    std::unique_ptr<Impl> m_impl;
    friend class AuthenticationWin;
};

BTH_EXPORT std::basic_ostream<char, std::char_traits<char>>& operator<<(std::basic_ostream<char, std::char_traits<char>>& stream,
                                                                        BTH::Device::MajorDeviceClass major);
} // namespace BTH
